﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Amazon.DynamoDBv2.Model;
using Amazon.Runtime.Internal.Util;
using ThirdParty.Json.LitJson;

namespace AmazonDynamoDBStub.Extensions
{
    public static class AttributeValueExtensions
    {
        public static string GetAttributeValue(this AttributeValue attributeValue)
        {
            if (attributeValue == null)
            {
                throw new ArgumentNullException("attributeValue");
            }

            using (StringWriter stringWriter = new StringWriter())
            {
                JsonWriter writer = new JsonWriter(stringWriter);

                switch (attributeValue.GetAttributeType())
                {
                    case "S":
                        return attributeValue.S;
                    case "N":
                        return attributeValue.N;
                    case "B":
                        return StringUtils.FromMemoryStream(attributeValue.B);
                    case "SS":
                        List<string> sSList = attributeValue.SS;
                        writer.WriteArrayStart();

                        foreach (string sSListValue in sSList)
                        {
                            writer.Write(StringUtils.FromString(sSListValue));
                        }

                        writer.WriteArrayEnd();
                        break;
                    case "NS":
                        List<string> nSList = attributeValue.NS;
                        writer.WriteArrayStart();

                        foreach (string nSListValue in nSList)
                        {
                            writer.Write(StringUtils.FromString(nSListValue));
                        }

                        writer.WriteArrayEnd();
                        break;
                    case "BS":
                        List<MemoryStream> bSList = attributeValue.BS;
                        writer.WriteArrayStart();

                        foreach (MemoryStream bSListValue in bSList)
                        {
                            writer.Write(StringUtils.FromMemoryStream(bSListValue));
                        }

                        writer.WriteArrayEnd();
                        break;
                    default:
                        break;
                }

                return stringWriter.ToString();
            }
        }

        public static string GetAttributeType(this AttributeValue attributeValue)
        {
            if (attributeValue != null && attributeValue.S != null)
            {
                return "S";
            }
            if (attributeValue != null && attributeValue.N != null)
            {
                return "N";
            }
            if (attributeValue != null && attributeValue.B != null)
            {
                return "B";
            }
            if (attributeValue != null && attributeValue.SS != null && attributeValue.SS.Count > 0)
            {
                return "SS";
            }
            if (attributeValue != null && attributeValue.NS != null && attributeValue.NS.Count > 0)
            {
                return "NS";
            }
            if (attributeValue != null && attributeValue.BS != null && attributeValue.BS.Count > 0)
            {
                return "BS";
            }

            throw new NotSupportedException("AttributeValue is not assigned with any value.");
        }

        public static bool IsArray(this AttributeValue attributeValue)
        {
            string[] arrayAttributeTypes = { "SS", "NS", "BS" };

            return arrayAttributeTypes.Contains(attributeValue.GetAttributeType());
        }

        public static bool IsNullOrEmpty(this AttributeValue value)
        {
            if (value.IsArray())
            {
                return value.SS.Count == 0 && value.NS.Count == 0 && value.BS.Count == 0;
            }

            return (value.S == null || value.S.Length == 0) && 
                (value.N == null || value.N.Length == 0) &&
                (value.B == null || value.B.Length == 0);
        }

        public static AttributeValue WithValue(this AttributeValue attributeValue, string value, string type)
        {
            switch (type)
            {
                case "S":
                    attributeValue.S = value;
                    break;
                case "N":
                    attributeValue.N = value;
                    break;
                case "B":
                    attributeValue.B = new MemoryStream(Convert.FromBase64String(value));
                    break;
                case "SS":
                case "NS":
                case "BS":
                    var values = JsonMapper.ToObject<List<string>>(new JsonReader(value));
                    attributeValue.WithValues(values, type);
                    break;
            }

            return attributeValue;
        }

        public static AttributeValue WithValues(this AttributeValue attributeValue, IEnumerable<string> values, string type)
        {
            switch (type)
            {
                case "SS":
                    attributeValue.SS = values.ToList();
                    break;
                case "NS":
                    attributeValue.NS = values.ToList();
                    break;
                case "BS":
                    attributeValue.BS = values.Select(value => new MemoryStream(Convert.FromBase64String(value))).ToList();
                    break;
            }

            return attributeValue;
        }
    }
}
